﻿using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Web;
using System.Xml;
using Newtonsoft.Json;

namespace Tools
{
    /// <summary>
    ///     字符处理器
    /// </summary>
    public static class Character
    {
        #region 字符加密 DES、AES、RC6、TEA、RAS、MD5、SHA1、SHA256

        // ReSharper disable InconsistentNaming
        public class MD5
        {
            private const string MD5Key = "-DONGYAN-DEFAULT";
            // ReSharper restore InconsistentNaming

            /// <summary>
            ///     MD5加密,位数补零
            /// </summary>
            /// <param name="prestr">需要加密的字符串</param>
            /// <param name="key">秘钥。可为空，为空则加密内容为prester，否则加密内容为"prester"+"key"</param>
            /// <param name="encoding">编码格式</param>
            /// <returns>加密结果</returns>
            public static string Encrypt(string prestr, string key, Encoding encoding)
            {
                if (string.IsNullOrEmpty(prestr))
                    throw new ArgumentNullException("prestr");

                var encryptContent = String.IsNullOrEmpty(key) ? prestr : prestr + key;
                var inbuf = encoding.GetBytes(encryptContent);
                var outbuf = System.Security.Cryptography.MD5.Create().ComputeHash(inbuf);
                //var stringBuilder = new StringBuilder(32);
                //foreach (byte item in outbuf)
                //{

                //    stringBuilder.AppendFormat("{0:X2}", item);
                //    //stringBuilder.Append(item.ToString("x").PadLeft(2, '0'));
                //}
                //return stringBuilder.ToString();
                return BitConverter.ToString(outbuf).Replace("-", "");
            }

            /// <summary>
            /// UTF-8内设的秘钥加密
            /// </summary>
            /// <param name="prestr">UTF-8</param>
            /// <returns></returns>
            public static string DefaultEncrypt(string prestr)
            {
                return Encrypt(prestr, MD5Key, Encoding.UTF8);
            }


        }

        // ReSharper disable InconsistentNaming
        public class AES
        {
            private const String AESKey = "AES@DONG";
            // ReSharper restore InconsistentNaming

            /// <summary>
            /// 对称算法的秘钥,unicode
            /// </summary>
            /// <param name="key">对称算法的秘钥</param>
            /// <returns></returns>
            private static byte[] GrenKey(string key)
            {
                return Encoding.Unicode.GetBytes(key);
            }

            /// <summary>
            /// 对称算法的秘钥,unicode
            /// </summary>
            /// <param name="key">对称算法的秘钥</param>
            /// <returns></returns>
            // ReSharper disable InconsistentNaming
            private static byte[] GrenVI(string key)
            // ReSharper restore InconsistentNaming
            {
                return Encoding.Unicode.GetBytes(key);
            }


            /// <summary>
            /// DES加密字符串
            /// </summary>
            /// <param name="prestr">待加密的字符串</param>
            /// <param name="key">对称算法的秘钥</param>
            /// <returns>加密成功返回加密后的Base64字符串</returns>
            public static string Encrypt(string prestr, string key)
            {
                if (String.IsNullOrEmpty(prestr))
                    throw new ArgumentNullException("prestr");
                if (String.IsNullOrEmpty(key))
                    throw new ArgumentNullException("key");
                if (key.Trim().Length != 8)
                    throw new ArgumentOutOfRangeException("key", "need Length != 8");


                byte[] encrypted;
                using (var aesAlg = new AesCryptoServiceProvider())
                {
                    aesAlg.Key = GrenKey(key);
                    aesAlg.IV = GrenVI(key);
                    /*
                    if (aesAlg.Key == null)
                        throw new ArgumentNullException("encryptString");
                    */
                    ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);

                    using (var msEncrypt = new MemoryStream())
                    {
                        using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                        {
                            using (var swEncrypt = new StreamWriter(csEncrypt))
                            {
                                swEncrypt.Write(prestr);
                            }
                        }
                        encrypted = msEncrypt.ToArray();
                    }

                }
                return Convert.ToBase64String(encrypted);
            }

            /// <summary>
            /// AES解密字符串
            /// </summary>
            /// <param name="encryptedString">待解密的Base64字符串</param>
            /// <param name="key">不含空格，8个字符</param>
            /// <returns>解密成功返回解密后的字符串</returns>
            public static string Decrypt(string encryptedString, string key)
            {
                if (string.IsNullOrEmpty(encryptedString))
                    throw new ArgumentNullException("encryptedString");
                if (string.IsNullOrEmpty(key))
                    throw new ArgumentNullException("key");
                if (key.Trim().Length != 8)
                    throw new ArgumentOutOfRangeException("key", "Length != 8");

                byte[] cipherText = Convert.FromBase64String(encryptedString);

                string plaintext;

                using (var aesAlg = new AesCryptoServiceProvider())
                {
                    aesAlg.Key = GrenKey(key);
                    aesAlg.IV = GrenKey(key);

                    // Create a decrytor to perform the stream transform.
                    ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);

                    // Create the streams used for decryption.
                    using (MemoryStream msDecrypt = new MemoryStream(cipherText))
                    {
                        using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                        {
                            using (StreamReader srDecrypt = new StreamReader(csDecrypt))
                            {
                                // Read the decrypted bytes from the decrypting stream
                                // and place them in a string.
                                plaintext = srDecrypt.ReadToEnd();
                            }
                        }
                    }
                }

                return plaintext;

            }

            /// <summary>
            /// 默认秘钥加密
            /// </summary>
            /// <param name="prestr">要加密的字符串</param>
            /// <returns>加密后的字符串(Base64)</returns>
            public static string EncryptByDefault(string prestr)
            {
                return Encrypt(prestr, AESKey);
            }

            /// <summary>
            /// 默认秘钥解密
            /// </summary>
            /// <param name="encryptedString">要解密的字符串</param>
            /// <returns>解密的字符串</returns>
            public static string DecryptByDefault(string encryptedString)
            {
                return Decrypt(encryptedString, AESKey);
            }


        }

        // ReSharper disable InconsistentNaming
        /// <summary>
        /// C#的RSA加密不是标准RSA，为了加强安全性，它强制使用了PKCS1填充（或OAEP填充）
        /// </summary>
        public class RSA
        // ReSharper restore InconsistentNaming
        {
            /// <summary>
            /// 公钥：发送方保存
            /// </summary>
            public static string PubKey { get; set; }

            /// <summary>
            /// 秘钥：接收方保存
            /// </summary>
            public static string PrvtKey { get; set; }

            /// <summary>
            /// 由接收方产生公钥密钥
            /// </summary>
            public static void GenKey(int dwKeySize)
            {
                var rsaProvider = new RSACryptoServiceProvider(dwKeySize);
                PubKey = rsaProvider.ToXmlString(false);
                PrvtKey = rsaProvider.ToXmlString(true);
            }

            /// <summary>
            ///     发送方用公钥加密
            /// </summary>
            /// <param name="prestr">需要加密的字符</param>
            /// <param name="publicKey">公钥</param>
            /// <param name="inputCharset">加密字符的编码</param>
            /// <returns>加密后的整数序列编码为base64</returns>
            public static string Encrypt(string prestr, string publicKey, string inputCharset)
            {
                if (string.IsNullOrEmpty(prestr))
                    throw new ArgumentNullException("prestr");
                if (string.IsNullOrEmpty(publicKey))
                    throw new ArgumentNullException("publicKey");
                if (string.IsNullOrEmpty(inputCharset))
                    throw new ArgumentNullException("inputCharset");

                byte[] data = Encoding.GetEncoding(inputCharset).GetBytes(prestr);

                using (var rsa = new RSACryptoServiceProvider(1024))
                {
                    rsa.FromXmlString(publicKey);
                    return Convert.ToBase64String(rsa.Encrypt(data, false));
                }
            }



            /// <summary>
            ///  接收方用私钥(+公钥)解密
            /// </summary>
            /// <param name="prestr">需要解密的Base64编码数据</param>
            /// <param name="privateKey">私钥</param>
            /// <returns>解密明文</returns>
            public static byte[] Decrypt(string prestr, string privateKey)
            {
                if (string.IsNullOrEmpty(prestr))
                    throw new ArgumentNullException("prestr");
                if (string.IsNullOrEmpty(privateKey))
                    throw new ArgumentNullException("privateKey");

                using (var rsa = new RSACryptoServiceProvider(1024))
                {
                    rsa.FromXmlString(privateKey);
                    return rsa.Decrypt(Convert.FromBase64String(prestr), false);
                }
            }

        }






        /// <summary>
        /// SHA1加密字符串
        /// </summary>
        /// <param name="sourceString">待加密的字符串</param>
        /// <param name="encoding">字符编码</param>
        /// <returns>加密后的字符</returns>
        // ReSharper disable InconsistentNaming
        public static string EncryptSHA1(string sourceString, Encoding encoding)
        // ReSharper restore InconsistentNaming
        {
            var strRes = new SHA1CryptoServiceProvider().ComputeHash(encoding.GetBytes(sourceString));
            var enText = new StringBuilder();
            foreach (byte iByte in strRes)
            {
                enText.AppendFormat("{0:x2}", iByte);
            }
            return enText.ToString();
        }

        /// <summary>
        /// HMACSHA1加密
        /// </summary>
        /// <param name="data">带加密的字节数组</param>
        /// <param name="secretKey">密钥</param>
        /// <returns></returns>
        public static byte[] EncryptHMACSHA1(byte[] data, byte[] secretKey)
        {
            HMACSHA1 hmac = new HMACSHA1(secretKey);
            byte[] digest = hmac.ComputeHash(data);
            return digest;
        }

        /// <summary>
        /// 转成base64url安全字符
        /// </summary>
        /// <param name="bs"></param>
        /// <returns></returns>
        public static string ConvertToBase64UrlSafe(byte[] bs)
        {
            return Convert.ToBase64String(bs).Replace('+', '-').Replace('/', '_');
        }


        #endregion

        #region HTML编码 URL编码

        public class Html
        {
            /// <summary>
            ///     Html编码
            /// </summary>
            /// <param name="str"></param>
            /// <returns></returns>
            public static string HtmlEncode(string str)
            {
                return HttpUtility.HtmlEncode(str);
            }

            /// <summary>
            ///     Html解码
            /// </summary>
            /// <param name="str"></param>
            /// <returns></returns>
            public static string HtmlDecode(string str)
            {
                return HttpUtility.HtmlDecode(str);
            }
        }

        public class Url
        {
            /// <summary>
            ///     URL编码
            /// </summary>
            /// <param name="str">需要编码的字符</param>
            /// <returns></returns>
            public static string UrlEncode(string str)
            {
                return HttpUtility.UrlEncode(str);
            }

            /// <summary>
            ///     URL编码
            /// </summary>
            /// <param name="str">需要编码的字符</param>
            /// <param name="e">需要制定的encoding对象</param>
            /// <returns></returns>
            public static string UrlEncode(string str, Encoding e)
            {
                return HttpUtility.UrlEncode(str, e);
            }


            /// <summary>
            ///     URL解码
            /// </summary>
            /// <param name="str">需要解码的URL字符串</param>
            /// <returns></returns>
            public static string UrlDecode(string str)
            {
                return HttpUtility.UrlDecode(str);
            }
        }


        #endregion


        #region XML处理

        /// <summary>
        ///  TODO:XML处理
        /// </summary>
        /// <param name="postStr"></param>
        public static void Xml(String postStr)
        {
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(postStr);

            XmlElement rootElement = doc.DocumentElement;
            XmlNode MsgType = rootElement.SelectSingleNode("MsgType");

            //MsgType.InnerText;
        }

        #endregion

        #region 格式化字符



        #endregion

        #region 常见数字判断

        /// <summary>
        /// 是否为2的幂数
        /// </summary>
        /// <param name="number"></param>
        /// <returns></returns>
        public static bool IsPowerOfTwo(ulong number)
        {
            return (number != 0) && ((number & (number - 1)) == 0);
        }

        #endregion


    }
}
